#include <iostream>
#include <string>
#include <list>
#include <memory>

using std::cout;
using std::endl;
using std::string;
using std::list;
using std::unique_ptr;

class Observe
{
public:
    virtual void update(int x) = 0;
    virtual ~Observe(){}
};

class ConcreteObserve1
:public Observe 
{
public:
    ConcreteObserve1(const string &name)
    :_name(name)
    {
        cout << "ConcreteObserve1(const string &name)" << endl;
    }

    void update(int x){
        cout << "ConcreteObserve1 name = " << _name
             << " " << x << endl;
    }

    ~ConcreteObserve1(){
        cout << "~ConcreteObserve1()" << endl;
    }
private:
    string _name;

};

class ConcreteObserve2
:public Observe 
{
public:
    ConcreteObserve2(const string &name)
    :_name(name)
    {
        cout << "ConcreteObserve2(const string &name)" << endl;
    }

    void update(int x){
        cout << "ConcreteObserve2 name = " << _name
             << " " << x << endl;
    }

    ~ConcreteObserve2(){
        cout << "~ConcreteObserve2()" << endl;
    }
private:
    string _name;

};

class Subject{
public:
    virtual void attach(Observe *p) = 0;
    virtual void detach(Observe *p) = 0;
    virtual void notify() = 0;
    virtual ~Subject(){} 
};

class ConcreteSubject
:public Subject 
{
public:
    void attach(Observe *p){
        if(p){
            _oblist.push_back(p);
        }
    }
    void detach(Observe *p){
        if(p){
            _oblist.remove(p);
        }
    }
    void notify(){
        for(auto &ob:_oblist){
            ob->update(_status);
        }
    }

    void setStatus(int status){
        _status = status;
    }
    int getStatus(){
        return _status;
    }

private:
    list<Observe *> _oblist;
    int _status;
};

void test(){
    unique_ptr<Observe> p1(new ConcreteObserve1("xww"));
    unique_ptr<Observe> p2(new ConcreteObserve1("sky"));

    unique_ptr<ConcreteSubject> s1(new ConcreteSubject());
    
    s1->attach(p1.get());
    s1->attach(p2.get());

    s1->setStatus(1);

    s1->notify();

    cout << endl << endl;
    s1->detach(p2.get());
    
    s1->setStatus(3);

    s1->notify();

}

int main()
{
    test();
    return 0;
}

